`include "define.v"

module id (
    input wire rst,
    input wire[`InstAddrBus] pc_i,
    input wire[`InstBus] inst_i,
    input wire[`RegBus] reg1_data_i,
    input wire[`RegBus] reg2_data_i,

    //数据相关的处理
    input wire ex_write_reg_enable_i,
    input wire[`RegAddrBus] ex_write_reg_addr_i,
    input wire[`RegBus] ex_write_data_i,
    input wire                    is_in_delayslot_i,

    input wire mem_write_reg_enable_i,
    input wire[`RegAddrBus] mem_write_reg_addr_i,
    input wire[`RegBus] mem_write_data_i,
    input wire[`AluOpBus] ex_aluop_i,

    //对接regfile的输出
    output reg reg1_read_enable_o,
    output reg reg2_read_enable_o,
    output reg[`RegAddrBus] reg1_addr_o,
    output reg[`RegAddrBus] reg2_addr_o,

    //对接id_exe的输出
    output reg[`AluOpBus] aluop_o,
    output reg[`AluSelBus] alusel_o,
    output reg[`RegBus] reg1_data_o,
    output reg[`RegBus] reg2_data_o,
    output reg[`RegAddrBus] write_reg_addr_o,
    output reg write_reg_enable,

    output reg                    next_inst_in_delayslot_o,
	
	output reg                    branch_flag_o,
	output reg[`RegBus]           branch_target_address_o,       
	output reg[`RegBus]           link_addr_o,
	output reg                    is_in_delayslot_o,
    output wire[`RegBus] inst_o,
    output wire[31:0]             excepttype_o,
    output wire[`RegBus]          current_inst_address_o,

    //ctrl
    output wire                   stallreq
);

    wire[5:0] op = inst_i[31:26];
    wire[4:0] op2 = inst_i[10:6];
    wire[5:0] op3 = inst_i[5:0];
    wire[4:0] op4 = inst_i[20:16];

    wire[`RegBus] pc_plus_8;
    wire[`RegBus] pc_plus_4;
    wire[`RegBus] imm_sll2_signedext;

    reg[`RegBus] imm;
    reg instvalid;
    reg stallreq_for_reg1_loadrelate;
    reg stallreq_for_reg2_loadrelate;
    assign pc_plus_8 = pc_i + 8;
    assign pc_plus_4 = pc_i + 4;
    assign imm_sll2_signedext = {{14{inst_i[15]}}, inst_i[15:0], 2'b00 }; 
    assign inst_o = inst_i;

    reg excepttype_is_syscall;
    reg excepttype_is_eret;

    assign pre_inst_is_load = ((ex_aluop_i == `EXE_LB_OP) || 
  													(ex_aluop_i == `EXE_LBU_OP)||
  													(ex_aluop_i == `EXE_LH_OP) ||
  													(ex_aluop_i == `EXE_LHU_OP)||
  													(ex_aluop_i == `EXE_LW_OP) ||
  													(ex_aluop_i == `EXE_LWR_OP)||
  													(ex_aluop_i == `EXE_LWL_OP)||
  													(ex_aluop_i == `EXE_LL_OP) ||
  													(ex_aluop_i == `EXE_SC_OP)) ? 1'b1 : 1'b0;

    assign excepttype_o = {19'b0,excepttype_is_eret,2'b0,
                                            instvalid, excepttype_is_syscall,8'b0};
    assign current_inst_address_o = pc_i;

    always @(*) begin
        if (rst == `RstEnable) begin
            aluop_o <= `EXE_NOP_OP;
			alusel_o <= `EXE_RES_NOP;
			write_reg_addr_o <= `NOPRegAddr;
			write_reg_enable <= `WriteDisable;
			instvalid <= `InstValid;
			reg1_read_enable_o <= 1'b0;
			reg2_read_enable_o <= 1'b0;
			reg1_addr_o <= `NOPRegAddr;
			reg2_addr_o <= `NOPRegAddr;
			imm <= 32'h0;

            link_addr_o <= `ZeroWord;
			branch_target_address_o <= `ZeroWord;
			branch_flag_o <= `NotBranch;
			next_inst_in_delayslot_o <= `NotInDelaySlot;

            excepttype_is_syscall <= `False_v;
			excepttype_is_eret <= `False_v;			
        end else begin
            aluop_o <= `EXE_NOP_OP;
			alusel_o <= `EXE_RES_NOP;
			write_reg_addr_o <= inst_i[15:11];
			write_reg_enable <= `WriteDisable;
			instvalid <= `InstInvalid;
			reg1_read_enable_o <= 1'b0;
			reg2_read_enable_o <= 1'b0;
			reg1_addr_o <= inst_i[25:21];
			reg2_addr_o <= inst_i[20:16];
			imm <= `ZeroWord;

            link_addr_o <= `ZeroWord;
			branch_target_address_o <= `ZeroWord;
			branch_flag_o <= `NotBranch;	
			next_inst_in_delayslot_o <= `NotInDelaySlot; 

			excepttype_is_syscall <= `False_v;	
			excepttype_is_eret <= `False_v;	
            case (op)
                `EXE_ORI: begin
                    write_reg_enable <= `WriteEnable;
                    aluop_o <= `EXE_OR_OP;
                    alusel_o <= `EXE_RES_LOGIC;
                    reg1_read_enable_o <= `ReadEnable;
                    reg2_read_enable_o <= `ReadDisable;
                    imm <= {16'h0, inst_i[15:0]};
                    write_reg_addr_o <= inst_i[20:16];
                    instvalid <= `InstValid;
                end
                `EXE_LL:			begin
		  		    write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_LL_OP;
		  		    alusel_o <= `EXE_RES_LOAD_STORE; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;	  	
					write_reg_addr_o <= inst_i[20:16]; instvalid <= `InstValid;	
				end
				`EXE_SC:			begin
		  		    write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_SC_OP;
		  		    alusel_o <= `EXE_RES_LOAD_STORE; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1;	  	
					write_reg_addr_o <= inst_i[20:16]; instvalid <= `InstValid;	
					alusel_o <= `EXE_RES_LOAD_STORE; 
				end		
                `EXE_SPECIAL_INST:		begin
                    case (op2)
                        5'b00000:			begin
                            case (op3)
                                `EXE_TEQ: begin
                                    write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_TEQ_OP;
                                    alusel_o <= `EXE_RES_NOP;   reg1_read_enable_o <= 1'b0;	reg2_read_enable_o <= 1'b0;
                                    instvalid <= `InstValid;
                                end
                                `EXE_TGE: begin
                                    write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_TGE_OP;
                                    alusel_o <= `EXE_RES_NOP;   reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1;
                                    instvalid <= `InstValid;
                                end		
                                `EXE_TGEU: begin
                                    write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_TGEU_OP;
                                    alusel_o <= `EXE_RES_NOP;   reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1;
                                    instvalid <= `InstValid;
                                end	
                                `EXE_TLT: begin
                                    write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_TLT_OP;
                                    alusel_o <= `EXE_RES_NOP;   reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1;
                                    instvalid <= `InstValid;
                                end
                                `EXE_TLTU: begin
                                    write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_TLTU_OP;
                                    alusel_o <= `EXE_RES_NOP;   reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1;
                                    instvalid <= `InstValid;
                                end	
                                `EXE_TNE: begin
                                    write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_TNE_OP;
                                    alusel_o <= `EXE_RES_NOP;   reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1;
                                    instvalid <= `InstValid;
                                end
                                `EXE_SYSCALL: begin
                                    write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_SYSCALL_OP;
                                    alusel_o <= `EXE_RES_NOP;   reg1_read_enable_o <= 1'b0;	reg2_read_enable_o <= 1'b0;
                                    instvalid <= `InstValid; excepttype_is_syscall<= `True_v;
                                end							 																					
                            	`EXE_DIV: begin
									write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_DIV_OP;
		  						    reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1; instvalid <= `InstValid;	
								end
								`EXE_DIVU: begin
									write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_DIVU_OP;
		  						    reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1; instvalid <= `InstValid;	
								end	
                                `EXE_OR:	begin
                                    write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_OR_OP;
                                    alusel_o <= `EXE_RES_LOGIC; 	reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1;
                                    instvalid <= `InstValid;	
                                end  
                                `EXE_AND:	begin
                                    write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_AND_OP;
                                    alusel_o <= `EXE_RES_LOGIC;	  reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1;	
                                    instvalid <= `InstValid;	
                                end  	
                                `EXE_XOR:	begin
                                    write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_XOR_OP;
                                    alusel_o <= `EXE_RES_LOGIC;		reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1;	
                                    instvalid <= `InstValid;	
                                end  				
                                `EXE_NOR:	begin
                                    write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_NOR_OP;
                                    alusel_o <= `EXE_RES_LOGIC;		reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1;	
                                    instvalid <= `InstValid;	
                                end 
                                `EXE_SLLV: begin
                                    write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_SLL_OP;
                                    alusel_o <= `EXE_RES_SHIFT;		reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1;
                                    instvalid <= `InstValid;	
                                end 
                                `EXE_SRLV: begin
                                    write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_SRL_OP;
                                    alusel_o <= `EXE_RES_SHIFT;		reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1;
                                    instvalid <= `InstValid;	
                                end 					
                                `EXE_SRAV: begin
                                    write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_SRA_OP;
                                    alusel_o <= `EXE_RES_SHIFT;		reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1;
                                    instvalid <= `InstValid;			
                                end			
                                `EXE_SYNC: begin
                                    write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_NOP_OP;
                                    alusel_o <= `EXE_RES_NOP;		reg1_read_enable_o <= 1'b0;	reg2_read_enable_o <= 1'b1;
                                    instvalid <= `InstValid;	
                                end
                                `EXE_MFHI: begin
                                    write_reg_enable <= `WriteEnable;
                                    aluop_o <= `EXE_MFHI_OP;
                                    alusel_o <= `EXE_RES_MOVE;
                                    reg1_read_enable_o <= `ReadDisable;
                                    reg2_read_enable_o <= `ReadDisable;
                                    instvalid <= `InstValid;
                                end
                                `EXE_MFLO: begin
                                    write_reg_enable <= `WriteEnable;
                                    aluop_o <= `EXE_MFLO_OP;
                                    alusel_o <= `EXE_RES_MOVE;
                                    reg1_read_enable_o <= `ReadDisable;
                                    reg2_read_enable_o <= `ReadDisable;
                                    instvalid <= `InstValid;
                                end
                                `EXE_MTHI: begin
                                    write_reg_enable <= `WriteEnable;
                                    aluop_o <= `EXE_MTHI_OP;
                                    alusel_o <= `EXE_RES_MOVE;
                                    reg1_read_enable_o <= `ReadEnable;
                                    reg2_read_enable_o <= `ReadDisable;
                                    instvalid <= `InstValid;
                                end		
                                `EXE_MTLO: begin
                                    write_reg_enable <= `WriteEnable;
                                    aluop_o <= `EXE_MTLO_OP;
                                    alusel_o <= `EXE_RES_MOVE;
                                    reg1_read_enable_o <= `ReadEnable;
                                    reg2_read_enable_o <= `ReadDisable;
                                    instvalid <= `InstValid;
                                end		
                                `EXE_MOVN: begin
                                    aluop_o <= `EXE_MOVN_OP;
                                    alusel_o <= `EXE_RES_MOVE;
                                    reg1_read_enable_o <= `ReadEnable;
                                    reg2_read_enable_o <= `ReadEnable;
                                    instvalid <= `InstValid;
                                    if (reg2_data_o != `ZeroWord) begin
                                        write_reg_enable <= `WriteEnable;
                                    end else begin
                                        write_reg_enable <= `WriteDisable;
                                    end
                                end
                                `EXE_MOVZ: begin
                                    aluop_o <= `EXE_MOVZ_OP;
                                    alusel_o <= `EXE_RES_MOVE;
                                    reg1_read_enable_o <= `ReadEnable;
                                    reg2_read_enable_o <= `ReadEnable;
                                    instvalid <= `InstValid;
                                    if (reg2_data_o == `ZeroWord) begin
                                        write_reg_enable <= `WriteEnable;
                                    end else begin
                                        write_reg_enable <= `WriteDisable;
                                    end
                                end
								`EXE_SLT: begin
									write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_SLT_OP;
		  						    alusel_o <= `EXE_RES_ARITHMETIC;		reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1;
		  						    instvalid <= `InstValid;	
								end
								`EXE_SLTU: begin
									write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_SLTU_OP;
		  						    alusel_o <= `EXE_RES_ARITHMETIC;		reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1;
		  						    instvalid <= `InstValid;	
								end
								`EXE_ADD: begin
									write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_ADD_OP;
		  						    alusel_o <= `EXE_RES_ARITHMETIC;		reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1;
		  						    instvalid <= `InstValid;	
								end
								`EXE_ADDU: begin
									write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_ADDU_OP;
		  						    alusel_o <= `EXE_RES_ARITHMETIC;		reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1;
		  						    instvalid <= `InstValid;	
								end
								`EXE_SUB: begin
									write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_SUB_OP;
		  						    alusel_o <= `EXE_RES_ARITHMETIC;		reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1;
		  						    instvalid <= `InstValid;	
								end
								`EXE_SUBU: begin
									write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_SUBU_OP;
		  						    alusel_o <= `EXE_RES_ARITHMETIC;		reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1;
		  						    instvalid <= `InstValid;	
								end
								`EXE_MULT: begin
									write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_MULT_OP;
		  						    reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1; instvalid <= `InstValid;	
								end
                                `EXE_JR: begin
									write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_JR_OP;
									alusel_o <= `EXE_RES_JUMP_BRANCH;   reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;
									link_addr_o <= `ZeroWord;
									
									branch_target_address_o <= reg1_data_o;
									branch_flag_o <= `Branch;
						
									next_inst_in_delayslot_o <= `InDelaySlot;
									instvalid <= `InstValid;	
								end
								`EXE_JALR: begin
									write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_JALR_OP;
									alusel_o <= `EXE_RES_JUMP_BRANCH;   reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;
									write_reg_addr_o <= inst_i[15:11];
									link_addr_o <= pc_plus_8;
		  						
									branch_target_address_o <= reg1_data_o;
									branch_flag_o <= `Branch;
			           
									next_inst_in_delayslot_o <= `InDelaySlot;
									instvalid <= `InstValid;	
								end	
								`EXE_MULTU: begin
									write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_MULTU_OP;
		  						    reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1; instvalid <= `InstValid;	
								end 											  									
                                default:	begin
                                end
                            endcase
                        end
                        default: begin
                        end
                    endcase	
				end
                `EXE_LB:			begin
		  		    write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_LB_OP;
		  		    alusel_o <= `EXE_RES_LOAD_STORE; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;	  	
					write_reg_addr_o <= inst_i[20:16]; instvalid <= `InstValid;	
				end
				`EXE_LBU:			begin
                    write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_LBU_OP;
                    alusel_o <= `EXE_RES_LOAD_STORE; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;	  	
					write_reg_addr_o <= inst_i[20:16]; instvalid <= `InstValid;	
				end
				`EXE_LH:			begin
                    write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_LH_OP;
                    alusel_o <= `EXE_RES_LOAD_STORE; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;	  	
					write_reg_addr_o <= inst_i[20:16]; instvalid <= `InstValid;	
				end
				`EXE_LHU:			begin
                    write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_LHU_OP;
                    alusel_o <= `EXE_RES_LOAD_STORE; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;	  	
					write_reg_addr_o <= inst_i[20:16]; instvalid <= `InstValid;	
				end
				`EXE_LW:			begin
                    write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_LW_OP;
                    alusel_o <= `EXE_RES_LOAD_STORE; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;	  	
					write_reg_addr_o <= inst_i[20:16]; instvalid <= `InstValid;	
				end
				`EXE_LL:			begin
                    write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_LL_OP;
                    alusel_o <= `EXE_RES_LOAD_STORE; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;	  	
					write_reg_addr_o <= inst_i[20:16]; instvalid <= `InstValid;	
				end
				`EXE_LWL:			begin
                    write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_LWL_OP;
                    alusel_o <= `EXE_RES_LOAD_STORE; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1;	  	
					write_reg_addr_o <= inst_i[20:16]; instvalid <= `InstValid;	
				end
				`EXE_LWR:			begin
                    write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_LWR_OP;
                    alusel_o <= `EXE_RES_LOAD_STORE; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1;	  	
					write_reg_addr_o <= inst_i[20:16]; instvalid <= `InstValid;	
				end
				`EXE_SB:			begin
                    write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_SB_OP;
                    reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1; instvalid <= `InstValid;	
                    alusel_o <= `EXE_RES_LOAD_STORE; 
				end
				`EXE_SH:			begin
                    write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_SH_OP;
                    reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1; instvalid <= `InstValid;	
                    alusel_o <= `EXE_RES_LOAD_STORE; 
				end
				`EXE_SW:			begin
                    write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_SW_OP;
                    reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1; instvalid <= `InstValid;	
                    alusel_o <= `EXE_RES_LOAD_STORE; 
				end
				`EXE_SWL:			begin
                    write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_SWL_OP;
                    reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1; instvalid <= `InstValid;	
                    alusel_o <= `EXE_RES_LOAD_STORE; 
				end
				`EXE_SWR:			begin
                    write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_SWR_OP;
                    reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1; instvalid <= `InstValid;	
                    alusel_o <= `EXE_RES_LOAD_STORE; 
				end
				`EXE_SC:			begin
                    write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_SC_OP;
                    alusel_o <= `EXE_RES_LOAD_STORE; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1;	  	
					write_reg_addr_o <= inst_i[20:16]; instvalid <= `InstValid;	
					alusel_o <= `EXE_RES_LOAD_STORE; 
				end				
                `EXE_J:			begin
                    write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_J_OP;
                    alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_enable_o <= 1'b0;	reg2_read_enable_o <= 1'b0;
                    link_addr_o <= `ZeroWord;
                    branch_target_address_o <= {pc_plus_4[31:28], inst_i[25:0], 2'b00};
                    branch_flag_o <= `Branch;
                    next_inst_in_delayslot_o <= `InDelaySlot;		  	
                    instvalid <= `InstValid;	
				end
				`EXE_JAL:			begin
                    write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_JAL_OP;
                    alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_enable_o <= 1'b0;	reg2_read_enable_o <= 1'b0;
                    write_reg_addr_o <= 5'b11111;	
                    link_addr_o <= pc_plus_8 ;
                    branch_target_address_o <= {pc_plus_4[31:28], inst_i[25:0], 2'b00};
                    branch_flag_o <= `Branch;
                    next_inst_in_delayslot_o <= `InDelaySlot;		  	
                    instvalid <= `InstValid;	
				end
                `EXE_BEQ:			begin
                    write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_BEQ_OP;
                    alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1;
                    instvalid <= `InstValid;	
                    if(reg1_data_o == reg2_data_o) begin
                        branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
                        branch_flag_o <= `Branch;
                        next_inst_in_delayslot_o <= `InDelaySlot;		  	
                    end
				end
				`EXE_BGTZ:			begin
                    write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_BGTZ_OP;
                    alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;
                    instvalid <= `InstValid;	
                    if((reg1_data_o[31] == 1'b0) && (reg1_data_o != `ZeroWord)) begin
                        branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
                        branch_flag_o <= `Branch;
                        next_inst_in_delayslot_o <= `InDelaySlot;		  	
                    end
				end
				`EXE_BLEZ:			begin
                    write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_BLEZ_OP;
                    alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;
                    instvalid <= `InstValid;	
                    if((reg1_data_o[31] == 1'b1) || (reg1_data_o == `ZeroWord)) begin
                        branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
                        branch_flag_o <= `Branch;
                        next_inst_in_delayslot_o <= `InDelaySlot;		  	
                    end
				end
				`EXE_BNE:			begin
                    write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_BLEZ_OP;
                    alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1;
                    instvalid <= `InstValid;	
                    if(reg1_data_o != reg2_data_o) begin
                        branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
                        branch_flag_o <= `Branch;
                        next_inst_in_delayslot_o <= `InDelaySlot;		  	
                    end
                end
		  	    `EXE_ANDI:			begin
                    write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_AND_OP;
                    alusel_o <= `EXE_RES_LOGIC;	reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;	  	
                    imm <= {16'h0, inst_i[15:0]};		write_reg_addr_o <= inst_i[20:16];		  	
                    instvalid <= `InstValid;	
				end	 	
		  	    `EXE_XORI:			begin
                    write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_XOR_OP;
                    alusel_o <= `EXE_RES_LOGIC;	reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;	  	
                    imm <= {16'h0, inst_i[15:0]};		write_reg_addr_o <= inst_i[20:16];		  	
                    instvalid <= `InstValid;	
				end	 		
		  	    `EXE_LUI:			begin
                    write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_OR_OP;
                    alusel_o <= `EXE_RES_LOGIC; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;	  	
                    imm <= {inst_i[15:0], 16'h0};		write_reg_addr_o <= inst_i[20:16];		  	
                    instvalid <= `InstValid;	
				end		
				`EXE_PREF:			begin
                    write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_NOP_OP;
                    alusel_o <= `EXE_RES_NOP; reg1_read_enable_o <= 1'b0;	reg2_read_enable_o <= 1'b0;	  	  	
                    instvalid <= `InstValid;	
				end	
				`EXE_SLTI:			begin
		  		    write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_SLT_OP;
		  		    alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;	  	
					imm <= {{16{inst_i[15]}}, inst_i[15:0]};		write_reg_addr_o <= inst_i[20:16];		  	
					instvalid <= `InstValid;	
				end
				`EXE_SLTIU:			begin
		  		    write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_SLTU_OP;
		  		    alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;	  	
					imm <= {{16{inst_i[15]}}, inst_i[15:0]};		write_reg_addr_o <= inst_i[20:16];		  	
					instvalid <= `InstValid;	
				end
				`EXE_ADDI:			begin
                    write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_ADDI_OP;
                    alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;	  	
					imm <= {{16{inst_i[15]}}, inst_i[15:0]};		write_reg_addr_o <= inst_i[20:16];		  	
					instvalid <= `InstValid;	
				end
				`EXE_ADDIU:			begin
                    write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_ADDIU_OP;
                    alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;	  	
					imm <= {{16{inst_i[15]}}, inst_i[15:0]};		write_reg_addr_o <= inst_i[20:16];		  	
					instvalid <= `InstValid;	
				end
                `EXE_REGIMM_INST:		begin
					case (op4)
						`EXE_BGEZ:	begin
							write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_BGEZ_OP;
                            alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;
                            instvalid <= `InstValid;	
                            if(reg1_data_o[31] == 1'b0) begin
                                branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
                                branch_flag_o <= `Branch;
                                next_inst_in_delayslot_o <= `InDelaySlot;		  	
                            end
						end
						`EXE_BGEZAL:		begin
							write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_BGEZAL_OP;
                            alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;
                            link_addr_o <= pc_plus_8; 
                            write_reg_addr_o <= 5'b11111;  	instvalid <= `InstValid;
                            if(reg1_data_o[31] == 1'b0) begin
                                branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
                                branch_flag_o <= `Branch;
                                next_inst_in_delayslot_o <= `InDelaySlot;
                            end
						end
						`EXE_BLTZ:		begin
						  write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_BGEZAL_OP;
                            alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;
                            instvalid <= `InstValid;	
                            if(reg1_data_o[31] == 1'b1) begin
                                branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
                                branch_flag_o <= `Branch;
                                next_inst_in_delayslot_o <= `InDelaySlot;		  	
                            end
						end
						`EXE_BLTZAL:		begin
							write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_BGEZAL_OP;
                            alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;
                            link_addr_o <= pc_plus_8;	
                            write_reg_addr_o <= 5'b11111; instvalid <= `InstValid;
                            if(reg1_data_o[31] == 1'b1) begin
                                branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
                                branch_flag_o <= `Branch;
                                next_inst_in_delayslot_o <= `InDelaySlot;
                            end
						end
                        `EXE_TEQI:			begin
                            write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_TEQI_OP;
                            alusel_o <= `EXE_RES_NOP; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;	  	
							imm <= {{16{inst_i[15]}}, inst_i[15:0]};		  	
							instvalid <= `InstValid;	
						end
						`EXE_TGEI:			begin
                            write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_TGEI_OP;
                            alusel_o <= `EXE_RES_NOP; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;	  	
							imm <= {{16{inst_i[15]}}, inst_i[15:0]};		  	
							instvalid <= `InstValid;	
						end
						`EXE_TGEIU:			begin
                            write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_TGEIU_OP;
                            alusel_o <= `EXE_RES_NOP; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;	  	
							imm <= {{16{inst_i[15]}}, inst_i[15:0]};		  	
							instvalid <= `InstValid;	
						end
						`EXE_TLTI:			begin
                            write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_TLTI_OP;
                            alusel_o <= `EXE_RES_NOP; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;	  	
							imm <= {{16{inst_i[15]}}, inst_i[15:0]};		  	
							instvalid <= `InstValid;	
						end
						`EXE_TLTIU:			begin
                            write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_TLTIU_OP;
                            alusel_o <= `EXE_RES_NOP; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;	  	
							imm <= {{16{inst_i[15]}}, inst_i[15:0]};		  	
							instvalid <= `InstValid;	
						end
						`EXE_TNEI:			begin
                            write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_TNEI_OP;
                            alusel_o <= `EXE_RES_NOP; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;	  	
							imm <= {{16{inst_i[15]}}, inst_i[15:0]};		  	
							instvalid <= `InstValid;	
						end					
						default:	begin
						end
					endcase
				end				
                `EXE_SPECIAL2_INST:		begin
					case ( op3 )
						`EXE_CLZ:		begin
							write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_CLZ_OP;
		  				    alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;	  	
							instvalid <= `InstValid;
						end
						`EXE_CLO:		begin
							write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_CLO_OP;
		  				    alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b0;	  	
							instvalid <= `InstValid;	
						end
						`EXE_MUL:		begin
							write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_MUL_OP;
                            alusel_o <= `EXE_RES_MUL; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1;	
                            instvalid <= `InstValid;	
						end
                        `EXE_MADD:		begin
                            write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_MADD_OP;
                            alusel_o <= `EXE_RES_MUL; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1;	  			
                            instvalid <= `InstValid;
						end
						`EXE_MADDU:		begin
                            write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_MADDU_OP;
                            alusel_o <= `EXE_RES_MUL; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1;	  			
                            instvalid <= `InstValid;
						end
						`EXE_MSUB:		begin
                            write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_MSUB_OP;
                            alusel_o <= `EXE_RES_MUL; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1;	  			
                            instvalid <= `InstValid;
						end
						`EXE_MSUBU:		begin
                            write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_MSUBU_OP;
                            alusel_o <= `EXE_RES_MUL; reg1_read_enable_o <= 1'b1;	reg2_read_enable_o <= 1'b1;	  			
                            instvalid <= `InstValid;
						end						
						default:	begin
						end
					endcase      //EXE_SPECIAL_INST2 case
				end										
                default:    begin
                    
                end
            endcase

            if (inst_i[31:21] == 11'b00000000000) begin
		  	    if (op3 == `EXE_SLL) begin
                    write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_SLL_OP;
                    alusel_o <= `EXE_RES_SHIFT; reg1_read_enable_o <= 1'b0;	reg2_read_enable_o <= 1'b1;	  	
                        imm[4:0] <= inst_i[10:6];		write_reg_addr_o <= inst_i[15:11];
                        instvalid <= `InstValid;	
				end else if ( op3 == `EXE_SRL ) begin
                    write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_SRL_OP;
                    alusel_o <= `EXE_RES_SHIFT; reg1_read_enable_o <= 1'b0;	reg2_read_enable_o <= 1'b1;	  	
                        imm[4:0] <= inst_i[10:6];		write_reg_addr_o <= inst_i[15:11];
                        instvalid <= `InstValid;	
				end else if ( op3 == `EXE_SRA ) begin
                    write_reg_enable <= `WriteEnable;		aluop_o <= `EXE_SRA_OP;
                    alusel_o <= `EXE_RES_SHIFT; reg1_read_enable_o <= 1'b0;	reg2_read_enable_o <= 1'b1;	  	
                        imm[4:0] <= inst_i[10:6];		write_reg_addr_o <= inst_i[15:11];
                        instvalid <= `InstValid;	
				end
			end	


            if(inst_i == `EXE_ERET) begin
				write_reg_enable <= `WriteDisable;		aluop_o <= `EXE_ERET_OP;
                alusel_o <= `EXE_RES_NOP;   reg1_read_enable_o <= 1'b0;	reg2_read_enable_o <= 1'b0;
                instvalid <= `InstValid; excepttype_is_eret<= `True_v;
            end else if(inst_i[31:21] == 11'b01000000000 && 
										inst_i[10:0] == 11'b00000000000) begin
				aluop_o <= `EXE_MFC0_OP;
				alusel_o <= `EXE_RES_MOVE;
				write_reg_addr_o <= inst_i[20:16];
				write_reg_enable <= `WriteEnable;
				instvalid <= `InstValid;
				reg1_read_enable_o <= 1'b0;
				reg2_read_enable_o <= 1'b0;
			end else if(inst_i[31:21] == 11'b01000000100 && 
										inst_i[10:0] == 11'b00000000000) begin
				aluop_o <= `EXE_MTC0_OP;
				alusel_o <= `EXE_RES_NOP;
				write_reg_enable <= `WriteDisable;
				instvalid <= `InstValid;	   
				reg1_read_enable_o <= 1'b1;
				reg1_addr_o <= inst_i[20:16];
				reg2_read_enable_o <= 1'b0;					
			end  
        end
    end

    always @ (*) begin
        stallreq_for_reg1_loadrelate <= `NoStop;
        if(rst == `RstEnable) begin
            reg1_data_o <= `ZeroWord;
        end else if(pre_inst_is_load == 1'b1 && ex_write_reg_addr_i == reg1_addr_o 
								&& reg1_read_enable_o == 1'b1 ) begin
		  stallreq_for_reg1_loadrelate <= `Stop;	
        end else if((reg1_read_enable_o == `ReadEnable) && (ex_write_reg_enable_i == `WriteEnable)
                        && (reg1_addr_o == ex_write_reg_addr_i)) begin
            reg1_data_o <= ex_write_data_i;
        end else if((reg1_read_enable_o == `ReadEnable) && (mem_write_reg_enable_i == `WriteEnable)
                && (reg1_addr_o == mem_write_reg_addr_i)) begin
            reg1_data_o <= mem_write_data_i;
        end else if(reg1_read_enable_o == 1'b1) begin
            reg1_data_o <= reg1_data_i;
        end else if(reg1_read_enable_o == 1'b0) begin
            reg1_data_o <= imm;
        end else begin
            reg1_data_o <= `ZeroWord;
        end
	end
	
	always @ (*) begin
        stallreq_for_reg2_loadrelate <= `NoStop;
		if(rst == `RstEnable) begin
			reg2_data_o <= `ZeroWord;
        end else if(pre_inst_is_load == 1'b1 && ex_write_reg_addr_i == reg2_addr_o 
								&& reg2_read_enable_o == 1'b1 ) begin
		  stallreq_for_reg2_loadrelate <= `Stop;	
        end else if((reg2_read_enable_o == `ReadEnable) && (ex_write_reg_enable_i == `WriteEnable)
                        && (reg2_addr_o == ex_write_reg_addr_i)) begin
            reg2_data_o <= ex_write_data_i;
        end else if((reg2_read_enable_o == `ReadEnable) && (mem_write_reg_enable_i == `WriteEnable)
                && (reg2_addr_o == mem_write_reg_addr_i)) begin
            reg2_data_o <= mem_write_data_i;
        end else if(reg2_read_enable_o == 1'b1) begin
            reg2_data_o <= reg2_data_i;
        end else if(reg2_read_enable_o == 1'b0) begin
            reg2_data_o <= imm;
        end else begin
            reg2_data_o <= `ZeroWord;
        end
	end

    assign stallreq = stallreq_for_reg1_loadrelate || stallreq_for_reg2_loadrelate;

    always @ (*) begin
		if(rst == `RstEnable) begin
            is_in_delayslot_o <= `NotInDelaySlot;
		end else begin
		    is_in_delayslot_o <= is_in_delayslot_i;		
	    end
	end
endmodule
